using System;
using System.Collections.Generic;
using System.Linq;
using Magiq.Delete;
using Magiq.Insert;
using Magiq.Query;
using Magiq.Support;
using Magiq.Update;

namespace Magiq.Tests.Support
{
    public class MagiqMock : MagiqProvider, IUpdateStrategy, IDeleteStrategy, IInsertStrategy
    {
        public MagiqMock() 
        {
            WasUsed = false;
            UpdateStrategy = this;
            DeleteStrategy = this;
            InsertStrategy = this;
            QueryStrategy = () => this;
        }

        public Func<object> QueryStrategy
        {
            get; set;
        }


        public IInsertStrategy InsertStrategy { get; set; }

        public IDeleteStrategy DeleteStrategy { get; set; }

        public static bool WasUsed { get; private set; }
        
        public bool Handles<T>(IEnumerable<T> source) where T : class
        {
            return true;
        }

        public int Execute<T>(IDelete<T> delete) where T : class
        {
            WasUsed = true;
            return 0;
        }

        public bool Handles<TSource, TDestination>(IEnumerable<TSource> source, IEnumerable<TDestination> destination) where TDestination : class
        {
            return true;
        }

        public int Execute<TSource, TDestination, TNew>(IInsert<TSource,TDestination, TNew> insert)
            where TNew : class
            where TDestination : class
        {
            WasUsed = true;
            return 0;
        }

        public IInsertDestination<TNew> Execute<TDestination, TNew>(IEnumerable<TDestination> destination)
            where TDestination : class
            where TNew : class
        {
            return new Adder<TNew>();
        }

        private class Adder<T> : IInsertDestination<T>
        {
            public void Insert(IEnumerable<T> items)
            {

            }
        }

        private IUpdateStrategy UpdateStrategy { get; set; }

        public override IUpdateStrategy GetUpdateStrategy<T>(IUpdate<T> update)
        {
            return UpdateStrategy;
        }

        public override IDeleteStrategy GetDeleteStrategy<T>(IDelete<T> delete)
        {
            return this;
        }

        public override IInsertStrategy GetInsertStrategy<TSource, TDestination, TNew>(IInsert<TSource,TDestination, TNew> insert)
        {
            return this;
        }

        public override IInsertDestination<TNew> GetInsertDestination<TSource, TDestination, TNew>(IInsert<TSource,TDestination, TNew> destination)
        {
            WasUsed = true;
            return new Adder<TNew>();
        }

        public override IQueryStrategy<TChild> GetQueryStrategy<T, TChild>(QueryInfo<T, TChild> queryInfo)
        {
            return new MockQueryStrategy<TChild>(queryInfo.Compiled.AsQueryable());
        }

        public override MagiqProviderOrderStrategy OrderStrategy
        {
            get { return MagiqProviderOrderStrategy.QueryInfoInCollection; }
        }

        public override IEnumerableStrategy<TNew> GetObjectSourceStrategy<TSource, TNew>(InsertSource<TNew> source)
        {
            return null;
        }

        public override IInsertStrategy GetBulkInsertStrategy<TSource, TDestination, TNew>(IInsert<TSource, TDestination, TNew> insert)
        {
            return null;
        }

        int IUpdateStrategy.Execute()
        {
            WasUsed = true;
            return 0;
        }

        int IDeleteStrategy.Execute()
        {
            WasUsed = true;
            return 0;
        }

        int IInsertStrategy.Execute()
        {
            WasUsed = true;
            return 0;
        }

        private class MockQueryStrategy<T> : IQueryStrategy<T>
        {
            private readonly IQueryable<T> queryable;

            public MockQueryStrategy(IQueryable<T> queryable) 
            {
                this.queryable = queryable;
            }

            public IQueryable<T> Execute()
            {
                WasUsed = true;
                return queryable;
            }
        }

        public static void AssertWasUsed()
        {
            WasUsed.Should(Be.True);
        }
    }
}